package xyz.hubery.task;

import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import xyz.hubery.domain.AsyncTask;
import xyz.hubery.dto.UpdateAccountDTO;
import xyz.hubery.enums.AsyncTaskStatus;
import xyz.hubery.enums.AsyncTaskType;
import xyz.hubery.feign.AccountServiceFeign;
import xyz.hubery.handler.AsyncTaskHandler;
import xyz.hubery.mapper.AsyncTaskMapper;
import xyz.hubery.model.R;
import xyz.hubery.model.TaskResult;
import xyz.hubery.service.EntrustOrderService;
import xyz.hubery.service.TurnoverOrderService;

/**
 * 更新账户余额处理器
 */
@Component
@Slf4j
public class UpdateAccountHandler implements AsyncTaskHandler {

    @Autowired
    private AccountServiceFeign accountServiceFeign;
    @Autowired
    private RedisTemplate<String,String> redisTemplate;
    @Autowired
    private AsyncTaskMapper asyncTaskMapper;
    
    @Override
    public AsyncTaskType getSupportedType() {
        return AsyncTaskType.UPDATE_ACCOUNT;
    }

    /**
     * 处理业务逻辑（更新账户余额
     * @param task
     * @return
     */
    @Transactional
    @Override
    public TaskResult handle(AsyncTask task) {
        // 幂等操作，防止同一多次操作
        if(Boolean.TRUE.equals(redisTemplate.hasKey(getSupportedType() + ":" + task.getId()))) {
            return TaskResult.success();
        }

        UpdateAccountDTO dto = JSON.parseObject(task.getPayload(), UpdateAccountDTO.class);
        
        try {

            // 调用资金服务更新余额
            R result = accountServiceFeign.updateAccountByExchangeTrade(dto);
            if (result.getCode()!=R.ok().getCode()) {
                throw new RuntimeException("资金结算失败");
            }

            redisTemplate.opsForValue().set(getSupportedType() + ":" + task.getId(),"");
            return TaskResult.success();
            
        } catch (Exception e) {
            log.error("账户余额更新失败, taskId: {}", task.getId(), e);
            return TaskResult.retry(e.getMessage());
        }
    }

    @Transactional
    @Override
    public void onSuccess(AsyncTask task, TaskResult result) {
        // 更新任务状态
        int i = asyncTaskMapper.updateStatus(task.getId(), task.getVersion(), AsyncTaskStatus.SUCCESS.getCode());
        if(i <= 0){ // 更新失败
            task.setMsg("异步任务更新失败 "+ task.getId());
            this.onRetry(task);
        }
    }

    @Override
    public void onFailure(AsyncTask task, TaskResult result) {
        // 重试次数+1，设置错误消息，
        task.setMsg(result.getMessage());
        task.setRetryCount(task.getRetryCount() + 1);
        asyncTaskMapper.failUpdate(task);
        // 重试
        this.onRetry(task);
    }

    @Override
    public void onRetry(AsyncTask task) {
        throw new RuntimeException("异步任务处理失败:"+task.getId() );
    }
}